use axum::{
    extract::{Path, State},
    http::StatusCode,
    Json,
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use sqlx_core::sqlite::SqlitePool;

#[derive(Serialize, Deserialize)]
pub struct NewPost {
    title: String,
    body: String,
}

#[derive(Serialize, Deserialize, sqlx::FromRow)]
pub struct Post {
    id: i32,
    title: String,
    body: String, 
}

pub async fn create_post(
    // 从全局路由状态获取数据库连接池
    State(pool): State<SqlitePool>,
    Json(product): Json<NewPost>,
) -> Result<Json<Value>, (StatusCode, String)> {
    let resp = sqlx::query("INSERT INTO posts (title, body) values ($1, $2)")
        // 填充占位符
        .bind(&product.title)
        .bind(&product.body)
        .execute(&pool)
        .await
        .map_err(|err| {
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Error is: {}", err),
            )
        })?;
    Ok(Json(json!(product)))
}

pub async fn get_posts(
    State(pool): State<SqlitePool>,
) -> Result<Json<Vec<Post>>, (StatusCode, String)> {
    let result = sqlx::query_as("SELECT * from posts")
        // 数据回填到结构体
        .fetch_all(&pool)
        .await
        .map_err(|err| {
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Error is: {}", err),
            )
        })?;
    Ok(Json(result))
}

pub async fn get_one_post(
    State(pool): State<SqlitePool>,
    Path(id): Path<i32>,
) -> Result<Json<Post>, (StatusCode, String)> {
    let result = sqlx::query_as("SELECT * FROM posts WHERE id = $1")
        .bind(id)
        .fetch_one(&pool)
        .await
        .map_err(|err| match err {
            sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, format!("Error is: {}", err)),
            _ => (
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Error is: {}", err),
            ),
        })?;
    Ok(Json(result))
}

pub async fn delete_post(
    State(pool): State<SqlitePool>,
    Path(id): Path<i32>,
) -> Result<Json<Value>, (StatusCode, String)> {
    let result = sqlx::query("DELETE FROM posts WHERE id = $1")
        .bind(id)
        .execute(&pool)
        .await
        .map_err(|err| match err {
            sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, format!("Error is: {}", err)),
            _ => (
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Error is: {}", err),
            ),
        })?;
    Ok(Json(json!({"msg": "Product deleted successfully"})))
}

pub async fn update_post(
    State(pool): State<SqlitePool>,
    Path(id): Path<i32>,
    Json(product): Json<Post>,
) -> Result<Json<Value>, (StatusCode, String)> {
    let result = sqlx::query("UPDATE posts SET title=$1, body=$2 WHERE id=$3")
        .bind(&product.title)
        .bind(&product.body)
        .bind(id)
        .execute(&pool)
        .await
        .map_err(|err| match err {
            sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, format!("Error is: {}", err)),
            _ => (
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Error is: {}", err),
            ),
        })?;
    Ok(Json(json!({"msg": "Product updated successfully"})))
}
